using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.IO;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using TheLogWatcher.Properties;

namespace TheLogWatcher
{
    class LogfileReader : LogfileAccess
    {
        public LogfileReader(Dictionary<MessageTypes, List<LogEntry>> data, string filename) : base(data,filename)
        {
        }

        /// <summary>
        ///     Reads a file and picks out the needed entry only.
        /// </summary>
        /// <param name="startOffsets">Startoffsets that will be searched in the file directly.</param>
        /// <returns>LogEntry</returns>
        public LogEntry readSingleEntry(LogFormat format, long fileStreamStartPos, long fileStreamEndPos)
        {
            this.startProcess("Reading next entry...");

            if (fileStreamStartPos >= fileStream.Length)
            {
                Console.WriteLine("readSingleEntry: File stream start offset is out of range.");
                return null;
            }
            if (fileStreamEndPos >= fileStream.Length)
            {
                Console.WriteLine("readSingleEntry: File stream end offset is out of range.");
                return null;
            }

            if (fileStreamEndPos == -1)
            {
                fileStreamEndPos = fileStream.Length;
            }

            Regex regex = new Regex(format.RegEx, RegexOptions.Multiline);

            this.fileStream.Position = fileStreamStartPos;
            int size = (int)(fileStreamEndPos - fileStreamStartPos);
            byte[] bytes = new byte[size];
            this.fileStream.Read(bytes, 0, size);

            // Look for the next linebreak after search position
            string s = Encoding.Default.GetString(bytes);
            Match match = regex.Match(s);
            GroupCollection groups = match.Groups;

            // Create a log entry object
            LogEntry entry = new LogEntry();
            string dateFormat = null;
            string timeFormat = null;
            foreach (LogFormat.Part item in format.Parts)
            {
                string value = groups[item.Title].Value;
                entry.Fields[item.Title] = value.Trim();
                if (item.Title.Equals("Date"))
	            {
                    dateFormat = item.Format;
                }
                else if (item.Title.Equals("Time"))
                {
                    timeFormat = item.Format;
                }
            }

            int startPos = match.Index + match.Length;
            string message = s.Substring(startPos, s.Length - startPos);

            this.incrementProgressBar();
            
            try
            {
                string date = entry.Fields["Date"];
                string time = entry.Fields["Time"];
                DateTime dt = DateTime.ParseExact(date + time, dateFormat + timeFormat, null);
                entry.Datetime = dt;

                // Find and remove first line break
                message = message.Trim();
                int firstLineBreak = message.IndexOf("\r\n");
                if (firstLineBreak != -1)
                {
                    message = message.Substring(0, firstLineBreak) + ' ' + message.Substring(firstLineBreak + 2);
                }
                entry.Fields["Log"] = message;
                entry.Type = MessageType.GetMessageType(entry.Fields["Type"]);
            }
            catch (Exception)
            {
                Console.WriteLine("readSingleEntry: Cannot create LogEntry. Maybe data is corrupt or timestamp is invalid.");
                return null;
            }

            this.stopProcess();

            return entry;
        }
    }
}
